#include"simulation/include/GenMultiBlockGrid.h"
#include"Utility/include/math.h"
#include"Utility/include/Timer.h"
#include<iostream>
#include<fstream>
void Zaran::GenMultiGridFromStarCD(MultiGrid& grid, StarCD& starcd_grid)
{
	vector<Point>nodeCoord = starcd_grid.GetNodeCoord();
	vector<int>boundFaceType = starcd_grid.GetBoundFaceType();
	vector<vector<int>>elementNodeIndex = starcd_grid.GetNodeInElementIndex();
	vector<vector<int>>boundFaceNodeIndex = starcd_grid.GetNodeInBoundFaceIndex();
	vector<Grid>gridVec;
	gridVec.resize(starcd_grid.GetBlockNum());
	// cycle all block
	for (size_t iGrid = 0; iGrid < gridVec.size(); ++iGrid)
	{
		vector<int>nodeBlockTag(starcd_grid.GetNodeNum());
		vector<int>nodeIndex(starcd_grid.GetNodeNum());
		for (size_t iNode = 0; iNode < nodeBlockTag.size(); ++iNode)
		{
			nodeBlockTag[iNode] = -1;
			nodeIndex[iNode] = iNode;
		}
		//grid.SetGridDim(iGrid,starcd_grid.GetDim());
		//grid.SetGridIndex(iGrid,iGrid);
		gridVec[iGrid].SetDim(starcd_grid.GetDim());
		gridVec[iGrid].SetIndex(iGrid);
		vector<int>elementBlockIndex(starcd_grid.GetElementNum());
		for (size_t iElem = 0; iElem < elementBlockIndex.size(); ++iElem)
		{
			elementBlockIndex[iElem] = starcd_grid.GetElementBlock(iElem);
		}
		for (size_t iElem = 0; iElem < starcd_grid.GetElementNum(); ++iElem)
		{
			if (elementBlockIndex[iElem] == iGrid + 1)
			{
				for (size_t iNode = 0; iNode < elementNodeIndex[iElem].size(); ++iNode)
				{
					nodeBlockTag[elementNodeIndex[iElem][iNode]] = iGrid;
				}
			}
		}
		int nodeNum = 0;
		vector<GridNode>gridNode;
		for (size_t iNode = 0; iNode < nodeBlockTag.size(); ++iNode)
		{
			if (nodeBlockTag[iNode] == iGrid)
			{
				nodeIndex[iNode] = nodeNum++;
				gridNode.push_back(GridNode{ &gridVec[iGrid], iNode, nodeCoord[iNode] });
			}
		}
		vector<GridElement>element;
		vector<size_t>ElementNodeIndex;
		for (size_t iElem = 0; iElem < starcd_grid.GetElementNum(); ++iElem)
		{
			if (elementBlockIndex[iElem] == iGrid + 1)
			{
				ElementNodeIndex.resize(elementNodeIndex[iElem].size());
				for (size_t iNode = 0; iNode < ElementNodeIndex.size(); ++iNode)
				{
					ElementNodeIndex[iNode] = nodeIndex[elementNodeIndex[iElem][iNode]];
				}
				element.push_back(GridElement(&gridVec[iGrid], ElementNodeIndex));
			}
		}

		vector<GridFace>face;
		// cycle all the element, check whether all of its faces are exist in grid
	// if not add it to the face vector
		vector<GridFace>faceVec;
		vector<size_t>faceIndexVec;
		vector<size_t>nodeIndexVec;
		size_t leftNode, rightNode;
		for (size_t iElem = 0; iElem < element.size(); ++iElem)
		{
			// PART I: get the face list from node list in the element
			nodeIndexVec = *element[iElem].GetNodeIndexVec();
			faceVec.resize(0);
			//the index of leftNode is smaller than rightNode 
			leftNode = std::min(nodeIndexVec.front(), nodeIndexVec.back());
			rightNode = std::max(nodeIndexVec.front(), nodeIndexVec.back());
			faceVec.push_back(GridFace(&gridVec[iGrid], vector<size_t>{leftNode, rightNode}));
			for (size_t iNode = 0; iNode < nodeIndexVec.size() - 1; ++iNode)
			{
				leftNode = std::min(nodeIndexVec[iNode], nodeIndexVec[iNode + 1]);
				rightNode = std::max(nodeIndexVec[iNode], nodeIndexVec[iNode + 1]);
				faceVec.push_back(GridFace(&gridVec[iGrid], vector<size_t>{leftNode, rightNode}));
			}
			// PART II:		check the faces in the elment whether exist in face list of grid
			// exist:		record the index of the face in face list
			// not exist:	push back the face to the face list of grid, record end index
			//				of face list
			faceIndexVec.resize(faceVec.size());
			for (size_t iFace = 0; iFace < faceVec.size(); ++iFace)
			{
				int faceIndex = -1;
				for (size_t jFace = 0; jFace < face.size(); ++jFace)
				{
					if (face[jFace] == faceVec[iFace])
					{
						faceIndex = jFace;
						break;
					}
				}
				if (faceIndex < 0)
				{
					face.push_back(faceVec[iFace]);
					faceIndexVec[iFace] = face.size() - 1;
				}
				else
				{
					faceIndexVec[iFace] = faceIndex;
				}
				face[faceIndexVec[iFace]].AddNeiborElement(iElem);
			}
			element[iElem].SetFaceIndex(faceIndexVec);
		}
		gridVec[iGrid].SetNode(gridNode);
		gridVec[iGrid].SetElement(element);
		gridVec[iGrid].SetFace(face);

		for (size_t iFace = 0; iFace < face.size(); ++iFace)
		{
			auto nodeIndex = face[iFace].GetNodeIndexVec();
			//2D face
			if (nodeIndex.size() == 2)
			{
				gridNode[nodeIndex[0]].AddNeiborNode(gridVec[iGrid].GetNode(nodeIndex[1]));
				gridNode[nodeIndex[1]].AddNeiborNode(gridVec[iGrid].GetNode(nodeIndex[0]));
			}
		}

		//		gridVec[iGrid].SetFaceFromElement();
///		gridVec[iGrid].SetNeiborNodeFromFace();
		vector<BoundType>nodeType;
		nodeType.resize(gridVec[iGrid].GetNodeNum());
		for (size_t iNode = 0; iNode < nodeType.size(); ++iNode)
		{
			nodeType[iNode] = BoundType::notbound;
		}
		for (size_t iFace = 0; iFace < starcd_grid.GetBoundFaceNum(); ++iFace)
		{

			for (size_t iNode = 0; iNode < boundFaceNodeIndex[iFace].size(); ++iNode)
			{
				int index = nodeIndex[boundFaceNodeIndex[iFace][iNode]];

				if (nodeBlockTag[boundFaceNodeIndex[iFace][iNode]] != iGrid)
					continue;
				if (nodeType[index] == BoundType::notbound)
				{
					if (boundFaceType[iFace] == 1/* && gridNode[index].x() < 0*/)
						nodeType[index] = BoundType::inlet;
					//if (boundFaceType[iFace] == 1 && gridNode[index].x() >= 0)
					//	nodeType[index] = BoundType::outlet;
					else if (boundFaceType[iFace] == 4)
						nodeType[index] = BoundType::interface;
					else if (gridVec[iGrid].GetNeiborNodeNum(index) == 2)
						nodeType[index] = BoundType::corner;
					else if (boundFaceType[iFace] == 2)
						nodeType[index] = BoundType::outlet;
					else if (boundFaceType[iFace] == 3)
						nodeType[index] = BoundType::solid_surface;
				}
			}
		}
		gridVec[iGrid].SetBoundNodeIndex();
	}
	grid.SetGridList(gridVec);
	grid.SetInterNode();
	grid.ReorderNeiborNode();
	grid.CalCoordTrans();
}